#include "stdafx.h"
#include "RenderLowFreq.h"

#include "Renderer.h"
#include "CSM.h"
#include "LoadShader.h"
#include "InputLayouts.h"
#include "Mesh.h"
#include "RenderingData.h"
#include "RenderingSettings.h"
#include "MyMath.h"

#include <d3dx9.h>

using namespace mgfx;

#define LIGHT_TEX_SIZE 16
#define NUM_LIGHT_TEX 6

TextureID LightTex[NUM_LIGHT_TEX];

#define BIG_LIGHT_TEX_SIZE 64
TextureID BigLightTex[NUM_LIGHT_TEX];
TextureID LightVolPosTex, LightVolScaleTex, LightVolSectionThreadOffsetXTex;


ShaderID CSBakeDirLight4;
ShaderID CSBakePointLight4;
ShaderID CSBakeSpotLight4;
ShaderID CSBakeShadowedSpotLight4;

ShaderID CSBakeDirLight6;
ShaderID CSBakePointLight6;
ShaderID CSBakeSpotLight6;
ShaderID CSBakeShadowedSpotLight6;

Mesh * TestMesh;
Mesh * BoxMesh;

float areaSideCoveredByGroup = 50.0f;
#define GROUP_SIZE 8
XMVECTOR BaseLightVolumeScale = XMVectorReplicate(areaSideCoveredByGroup / GROUP_SIZE);
XMVECTOR LightVolumeScale = BaseLightVolumeScale;
XMVECTOR LightVolumePos = XMVectorSet(0,0,0,0);
uint groupsX, groupsY, groupsZ;

ShaderID ShaderRenderObj;
static ShaderID ShaderRenderParticles4;
static ShaderID ShaderRenderParticles6;
static VertexBufferID vertexBuffer;
static IndexBufferID indexBuffer;

static bool use6Axes = true;

void mgfx::initLowFreq()
{
	ShaderRenderObj = loadShaderFromFile("RenderSH.fx");

	ShaderRenderParticles4 = loadShaderFromFile("RenderParticleWithProbes.fx", ShaderDefine("AXES_4", "1"));
	CSBakeDirLight4 = loadShaderFromFile("CSBakeDirLight.fx", ShaderDefine("AXES_4", "1"));
	CSBakePointLight4 = loadShaderFromFile("CSBakePointLight.fx", ShaderDefine("AXES_4", "1"));
	CSBakeSpotLight4 = loadShaderFromFile("CSBakeSpotLight.fx", ShaderDefine("AXES_4", "1"));
	CSBakeShadowedSpotLight4 = loadShaderFromFile("CSBakeSpotLight.fx", ShaderDefine("AXES_4", "1"), ShaderDefine("SHADOWS", "1"));

	ShaderRenderParticles6 = loadShaderFromFile("RenderParticleWithProbes.fx");
	CSBakeDirLight6 = loadShaderFromFile("CSBakeDirLight.fx");
	CSBakePointLight6 = loadShaderFromFile("CSBakePointLight.fx");
	CSBakeSpotLight6 = loadShaderFromFile("CSBakeSpotLight.fx");
	CSBakeShadowedSpotLight6 = loadShaderFromFile("CSBakeSpotLight.fx", ShaderDefine("SHADOWS", "1"));
	
	MeshDesc meshDesc;
	meshDesc.FileName = "sphere.ms3d";
	meshDesc.LoadTextures = false;
	TestMesh = Mesh::createFromFile(meshDesc);

	meshDesc.FileName = "box.ms3d";
	BoxMesh = Mesh::createFromFile(meshDesc);

	TwBar *myBar;
	myBar = TwNewBar("lowfreq");
	TwAddVarRW(myBar, "6 axes", TW_TYPE_BOOLCPP, &use6Axes, "");

	Renderer * rdr = Renderer::Instance;

	vertexBuffer = rdr->addVertexBuffer(NULL, ParticleSystem::MAX_PARTICLES * 4, sizeof(VertexParticle), true);

	short * indices = new short[ParticleSystem::MAX_PARTICLES * 6];
	for (uint i = 0; i < ParticleSystem::MAX_PARTICLES; i++)
	{
		indices[i*6 + 0] = i*4 + 0;
		indices[i*6 + 1] = i*4 + 1;
		indices[i*6 + 2] = i*4 + 2;

		indices[i*6 + 3] = i*4 + 0;
		indices[i*6 + 4] = i*4 + 2;
		indices[i*6 + 5] = i*4 + 3;
	}
	indexBuffer = rdr->addIndexBuffer(indices, ParticleSystem::MAX_PARTICLES * 6, sizeof(short), false);
	delete [] indices;
}

static void init3DTextures(const RenderingData & data)
{
	TextureDesc texDesc;
	texDesc.Type = TEXTURE3D;
	texDesc.Width = texDesc.Height = texDesc.Depth = LIGHT_TEX_SIZE;
	texDesc.Format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
	texDesc.CreateSRV = true;
	texDesc.CreateUAV = true;
	texDesc.SRVFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
	texDesc.UAVFormat = DXGI_FORMAT_R32_UINT;
	texDesc.Dynamic = false;
	texDesc.DataPitch = LIGHT_TEX_SIZE * 4;
	texDesc.DataSlicePitch = LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * 4;
	
	byte * dummyMem = new byte[LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * 4];
	for(uint i = 0; i < NUM_LIGHT_TEX; i++)
	{
		texDesc.Data = dummyMem;
		LightTex[i] = Renderer::Instance->addTexture3D(texDesc);
	}
	delete [] dummyMem;

	// big light tex
	texDesc.Width = BIG_LIGHT_TEX_SIZE;
	texDesc.Height = texDesc.Depth = LIGHT_TEX_SIZE;
	texDesc.DataPitch = BIG_LIGHT_TEX_SIZE * 4;
	texDesc.DataSlicePitch = BIG_LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * 4;

	dummyMem = new byte[BIG_LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * LIGHT_TEX_SIZE * 4];
	for(uint i = 0; i < NUM_LIGHT_TEX; i++)
	{
		texDesc.Data = dummyMem;
		BigLightTex[i] = Renderer::Instance->addTexture3D(texDesc);
	}
	
	delete [] dummyMem;

	// light pos and scale tex
	texDesc.Type = TEXTURE1D;
	texDesc.Width = BIG_LIGHT_TEX_SIZE / GROUP_SIZE;
	texDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
	texDesc.SRVFormat = DXGI_FORMAT_R32G32B32_FLOAT;
	texDesc.CreateUAV = false;
	texDesc.Dynamic = true;
	texDesc.Data = NULL;
	LightVolPosTex = Renderer::Instance->addTexture1D(texDesc);
	LightVolScaleTex = Renderer::Instance->addTexture1D(texDesc);

	texDesc.Format = DXGI_FORMAT_R16_UINT;
	texDesc.SRVFormat = DXGI_FORMAT_R16_UINT;
	LightVolSectionThreadOffsetXTex = Renderer::Instance->addTexture1D(texDesc);
}

static void setLightTextures()
{
	Renderer * rdr = Renderer::Instance;
	rdr->setShaderUAV("gLightTex0", BigLightTex[0]);
	rdr->setShaderUAV("gLightTex1", BigLightTex[1]);
	rdr->setShaderUAV("gLightTex2", BigLightTex[2]);
	if (use6Axes)
	{
		rdr->setShaderUAV("gLightTex3", BigLightTex[3]);
		rdr->setShaderUAV("gLightTex4", BigLightTex[4]);
	}

	rdr->setShaderResource("gLightVolPosTex", LightVolPosTex);
	rdr->setShaderResource("gLightVolScaleTex", LightVolScaleTex);
	rdr->setShaderResource("gLightVolSectionThreadOffsetXTex", LightVolSectionThreadOffsetXTex);
}

static void unsetLightTextures()
{
	Renderer * rdr = Renderer::Instance;
	rdr->setShaderUAV("gLightTex0", Renderer::TEXTURE_NONE);
	rdr->setShaderUAV("gLightTex1", Renderer::TEXTURE_NONE);
	rdr->setShaderUAV("gLightTex2", Renderer::TEXTURE_NONE);
	if (use6Axes)
	{
		rdr->setShaderUAV("gLightTex3", Renderer::TEXTURE_NONE);
		rdr->setShaderUAV("gLightTex4", Renderer::TEXTURE_NONE);
	}

	rdr->setShaderResource("gLightVolPosTex", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightVolScaleTex", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightVolSectionThreadOffsetXTex", Renderer::TEXTURE_NONE);

	rdr->applyConstantsWithoutDrawing();
}

static void bakeDirLight(const RenderingData & data, const CSM & csm)
{
	Renderer * rdr = Renderer::Instance;

	rdr->setShader(use6Axes ? CSBakeDirLight6 : CSBakeDirLight4);
	rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	rdr->setShaderFloatVector("gLightVolScale", (float*)&LightVolumeScale);

	const DirectionalLight & light = data.MainLight;
	float dirLightColorAndIntens[] = { light.Color.x, light.Color.y, light.Color.z, light.Intensity };
	rdr->setShaderFloatVector("gLightColorAndIntens", dirLightColorAndIntens);
	rdr->setShaderFloatVector("gLightDirW", (float*)&light.Direction);

	rdr->setShaderMatrix("gViewMatrix", (float*)&data.ViewMatrix);
	rdr->setShaderMatrixArray("gLightViewProjs", (float*)&csm.Matrices, CSM::NUM_CASCADES);
	rdr->setShaderFloatVector("gCascadeDepths", (float*)&csm.SplitDepths[1]);
	rdr->setShaderResource("gBigShadowMap", csm.AllCascadesMap);

	setLightTextures();
	rdr->dispatch(groupsX, groupsY, groupsZ);
	rdr->setShaderResource("gBigShadowMap", Renderer::TEXTURE_NONE);
	unsetLightTextures();
}

#define MAX_POINT_LIGHTS 128

struct PointLightData
{
	XMFLOAT4 PosAndRadius;
	XMFLOAT4 ColorAndIntens;
};

static PointLightData pointLightArray[MAX_POINT_LIGHTS];

static void bakePointLights(const RenderingData & data)
{
	assert(data.PointLights.NumElements <= MAX_POINT_LIGHTS);

	for(uint i = 0; i < data.PointLights.NumElements; i++)
	{
		const PointLight & light = data.PointLights[i];
		pointLightArray[i].PosAndRadius = XMFLOAT4(light.Position.x, light.Position.y, light.Position.z, light.Radius);
		pointLightArray[i].ColorAndIntens = XMFLOAT4(light.Color.x, light.Color.y, light.Color.z, light.Intensity);
	}

	Renderer * rdr = Renderer::Instance;

	rdr->setShader(use6Axes ? CSBakePointLight6 : CSBakePointLight4);
	rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	rdr->setShaderFloatVector("gLightVolScale", (float*)&LightVolumeScale);

	rdr->setShaderRawValue("gLights", pointLightArray, sizeof(PointLightData) * data.PointLights.NumElements);
	rdr->setShaderInt("gNumLights", (int)data.PointLights.NumElements);

	setLightTextures();
	rdr->dispatch(groupsX, groupsY, groupsZ);
	unsetLightTextures();
}

static void setSpotLightShaderParams(const SpotLight & light)
{
	Renderer * rdr = Renderer::Instance;

	float lightColorAndIntens[] = { light.Color.x, light.Color.y, light.Color.z, light.Intensity };
	rdr->setShaderFloatVector("gLightColorAndIntens", lightColorAndIntens);

	float lightPosAndRadius[] = { light.Position.x, light.Position.y, light.Position.z, light.Radius };
	rdr->setShaderFloatVector("gLightPosWAndRadius", lightPosAndRadius);

	XMVECTOR spotDir = XMVector3TransformNormal(
		SpotLight::InitialDirection,
		XMMatrixRotationQuaternion( XMLoadFloat4(&light.Orientation) )
	);
	spotDir = XMVectorSetW(spotDir, light.SpotCosAngle);
	rdr->setShaderFloatVector("gLightDirAndCosAngle", (float*)&spotDir);
}

static void bakeSpotLights(const RenderingData & data)
{
	Renderer * rdr = Renderer::Instance;

	// lights without shadows
	rdr->setShader(use6Axes ? CSBakeSpotLight6 : CSBakeSpotLight4);
	rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	rdr->setShaderFloatVector("gLightVolScale", (float*)&LightVolumeScale);

	setLightTextures();

	for(uint i = 0; i < data.SpotLights.NumElements; i++)
	{
		const SpotLight & light = data.SpotLights[i];

		if(light.IsCastingShadows)
			continue;

		setSpotLightShaderParams(light);

		rdr->dispatch(groupsX, groupsY, groupsZ);
	}

	unsetLightTextures();

	// lights with shadows
	rdr->setShader(use6Axes ? CSBakeShadowedSpotLight6 : CSBakeShadowedSpotLight4);
	rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	rdr->setShaderFloatVector("gLightVolScale", (float*)&LightVolumeScale);

	setLightTextures();

	for(uint i = 0; i < data.SpotLights.NumElements; i++)
	{
		const SpotLight & light = data.SpotLights[i];

		if(!light.IsCastingShadows)
			continue;

		setSpotLightShaderParams(light);

		XMVECTOR tmp;
		XMMATRIX lightViewProj = XMMatrixMultiply(
			XMMatrixInverse(&tmp, XMLoadFloat4x4(&light.WorldTransform)),
			XMLoadFloat4x4(&light.ProjectionMatrix)
		);

		rdr->setShaderMatrix("gLightViewProj", (float*)&lightViewProj);
		rdr->setShaderResource("gShadowMap", light.ShadowMap);
		
		rdr->dispatch(groupsX, groupsY, groupsZ);

		rdr->setShaderResource("gShadowMap", Renderer::TEXTURE_NONE);
	}

	unsetLightTextures();
}

static void updateLightTexturesCS(const RenderingData & data, uint partSysIndex, const CSM & csm)
{
	mmath::BoundingBox bbox = data.PartSystems[partSysIndex].MaxBoundingBox;
	bbox.scale(0.7f);

	XMVECTOR boxMin = XMLoadFloat3(&bbox.Min);
	XMVECTOR boxMax = XMLoadFloat3(&bbox.Max);

	boxMin = XMVectorAdd(boxMin, XMVectorSet(0, -15, 0, 0));
	boxMax = XMVectorAdd(boxMax, XMVectorSet(0, -15, 0, 0));

	XMVECTOR groupsNum = (boxMax - boxMin) * XMVectorReplicate(1.0f / areaSideCoveredByGroup);
	XMVECTOR groupsNumRounded = XMVectorCeiling(groupsNum);
	groupsX = (uint)XMVectorGetX(groupsNumRounded);
	groupsY = (uint)XMVectorGetY(groupsNumRounded);
	groupsZ = (uint)XMVectorGetZ(groupsNumRounded);

	LightVolumeScale = XMVectorMultiply(BaseLightVolumeScale, XMVectorDivide(groupsNum, groupsNumRounded));
	LightVolumePos = XMVectorAdd(boxMin, XMVectorMultiply(LightVolumeScale, XMVectorReplicate(0.5f)));

	bakeDirLight(data, csm);
	bakePointLights(data);	
	bakeSpotLights(data);	
}

static void renderParticles(const RenderingData & data, uint partSysIndex)
{
	Renderer * rdr = Renderer::Instance;

	rdr->setPrimitiveType(TRIANGLE_LIST);
	rdr->setVertexFormat(VertexParticle::VertexFormat);

	rdr->setIndexBuffer(indexBuffer);

	rdr->setShader(use6Axes ? ShaderRenderParticles6 : ShaderRenderParticles4);

	rdr->setShaderResource("gLightTex0", LightTex[0]);
	rdr->setShaderResource("gLightTex1", LightTex[1]);
	rdr->setShaderResource("gLightTex2", LightTex[2]);
	if(use6Axes)
	{
		rdr->setShaderResource("gLightTex3", LightTex[3]);
		rdr->setShaderResource("gLightTex4", LightTex[4]);
	}
	

	rdr->setShaderFloatVector("gLightVolScale", (float*)&LightVolumeScale);
	rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	rdr->setShaderFloatVector("gEyePosW",(float*)&data.EyePosition);

	XMMATRIX view, proj;
	view = XMLoadFloat4x4(&data.ViewMatrix);
	proj = XMLoadFloat4x4(&data.ProjMatrix);

	XMMATRIX viewProj = XMMatrixMultiply(view, proj);
	rdr->setShaderMatrix("gViewProjMatrix", (float*)&viewProj);

	const ParticleSystem & ps = data.PartSystems[partSysIndex];

	memcpy(rdr->mapVertexBuffer(vertexBuffer), ps.Vertices, ps.NumParticlesActive * 4 * sizeof(VertexParticle));
	rdr->unmapVertexBuffer(vertexBuffer);

	rdr->setVertexBuffer(vertexBuffer);

	rdr->setShaderResource("gDiffuseMap", ps.Desc.Texture);

	rdr->drawIndexed(ps.NumParticlesActive * 6);

	rdr->setShaderResource("gLightTex0", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightTex1", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightTex2", Renderer::TEXTURE_NONE);
	if(use6Axes)
	{
		rdr->setShaderResource("gLightTex3", Renderer::TEXTURE_NONE);
		rdr->setShaderResource("gLightTex4", Renderer::TEXTURE_NONE);
	}
	rdr->applyConstantsWithoutDrawing();
}

XMFLOAT3 LightVolPosTexData[BIG_LIGHT_TEX_SIZE / GROUP_SIZE];
XMFLOAT3 LightVolScaleTexData[BIG_LIGHT_TEX_SIZE / GROUP_SIZE];
unsigned short LightVolSectionThreadOffsetXTexData[BIG_LIGHT_TEX_SIZE / GROUP_SIZE];

static void renderParticlesBigTex(const RenderingData & data, TextureID dstBuffer, TextureID depthBuffer, const CSM & csm)
{
	groupsX = groupsY = groupsZ = 0;

	XMFLOAT3 lightVolPositions[16];
	XMFLOAT3 lightVolScales[16];
	float lightTexOffsetsX[16];

	for(uint i = 0; i < data.PartSystems.NumElements; i++)
	{
		mmath::BoundingBox bbox = data.PartSystems[i].MaxBoundingBox;
		bbox.scale(0.7f);

		XMVECTOR boxMin = XMLoadFloat3(&bbox.Min);
		XMVECTOR boxMax = XMLoadFloat3(&bbox.Max);

		boxMin = XMVectorAdd(boxMin, XMVectorSet(0, -15, 0, 0));
		boxMax = XMVectorAdd(boxMax, XMVectorSet(0, -15, 0, 0));

		XMVECTOR groupsNum = (boxMax - boxMin) * XMVectorReplicate(1.0f / areaSideCoveredByGroup);
		XMVECTOR groupsNumRounded = XMVectorCeiling(groupsNum);

		uint nextGroupsX = groupsX + (uint)XMVectorGetX(groupsNumRounded);

		if(nextGroupsX > BIG_LIGHT_TEX_SIZE / GROUP_SIZE)
		{
			LOG_ERROR("Too many transparent objects. 3D light texture too small");
			return;
		}

		XMStoreFloat3(&lightVolScales[i], XMVectorMultiply(BaseLightVolumeScale, XMVectorDivide(groupsNum, groupsNumRounded)));
		XMStoreFloat3(&lightVolPositions[i], XMVectorAdd(boxMin, XMVectorMultiply(LightVolumeScale, XMVectorReplicate(0.5f))));

		for(uint x = groupsX; x < nextGroupsX; x++)
		{
			LightVolPosTexData[x] = lightVolPositions[i];
			LightVolScaleTexData[x] = lightVolScales[i];
			LightVolSectionThreadOffsetXTexData[x] = groupsX * GROUP_SIZE;
		}

		lightTexOffsetsX[i] = (float)groupsX / (float)(BIG_LIGHT_TEX_SIZE / GROUP_SIZE);
		
		groupsX = nextGroupsX;
		groupsY = max(groupsY, (uint)XMVectorGetY(groupsNumRounded));
		groupsZ = max(groupsZ, (uint)XMVectorGetZ(groupsNumRounded));
	}

	Renderer * rdr = Renderer::Instance;

	memcpy(rdr->mapTexture(LightVolPosTex, NULL, NULL), LightVolPosTexData, BIG_LIGHT_TEX_SIZE / GROUP_SIZE * sizeof(XMFLOAT3));
	rdr->unmapTexture(LightVolPosTex);

	memcpy(rdr->mapTexture(LightVolScaleTex, NULL, NULL), LightVolScaleTexData, BIG_LIGHT_TEX_SIZE / GROUP_SIZE * sizeof(XMFLOAT3));
	rdr->unmapTexture(LightVolScaleTex);

	memcpy(rdr->mapTexture(LightVolSectionThreadOffsetXTex, NULL, NULL),
			LightVolSectionThreadOffsetXTexData,
			BIG_LIGHT_TEX_SIZE / GROUP_SIZE * sizeof(unsigned short));
	rdr->unmapTexture(LightVolSectionThreadOffsetXTex);

	bakeDirLight(data, csm);
	bakePointLights(data);	
	bakeSpotLights(data);

	rdr->setRenderTargets(1, &dstBuffer, depthBuffer);

	rdr->setPrimitiveType(TRIANGLE_LIST);
	rdr->setVertexFormat(VertexParticle::VertexFormat);

	rdr->setIndexBuffer(indexBuffer);

	rdr->setShader(use6Axes ? ShaderRenderParticles6 : ShaderRenderParticles4);

	rdr->setShaderResource("gLightTex0", BigLightTex[0]);
	rdr->setShaderResource("gLightTex1", BigLightTex[1]);
	rdr->setShaderResource("gLightTex2", BigLightTex[2]);
	if(use6Axes)
	{
		rdr->setShaderResource("gLightTex3", BigLightTex[3]);
		rdr->setShaderResource("gLightTex4", BigLightTex[4]);
	}

	rdr->setShaderFloatVector("gEyePosW",(float*)&data.EyePosition);

	XMMATRIX view, proj;
	view = XMLoadFloat4x4(&data.ViewMatrix);
	proj = XMLoadFloat4x4(&data.ProjMatrix);

	XMMATRIX viewProj = XMMatrixMultiply(view, proj);
	rdr->setShaderMatrix("gViewProjMatrix", (float*)&viewProj);
	
	for(uint i = 0; i < data.PartSystems.NumElements; i++)
	{
		rdr->setShaderFloatVector("gLightVolScale", (float*)&lightVolScales[i]);
		rdr->setShaderFloatVector("gLightVolPos", (float*)&lightVolPositions[i]);
		rdr->setShaderFloat("gLightTexOffsetX", lightTexOffsetsX[i]);

		const ParticleSystem & ps = data.PartSystems[i];

		memcpy(rdr->mapVertexBuffer(vertexBuffer), ps.Vertices, ps.NumParticlesActive * 4 * sizeof(VertexParticle));
		rdr->unmapVertexBuffer(vertexBuffer);

		rdr->setVertexBuffer(vertexBuffer);

		rdr->setShaderResource("gDiffuseMap", ps.Desc.Texture);

		rdr->drawIndexed(ps.NumParticlesActive * 6);
	}

	rdr->setShaderResource("gLightTex0", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightTex1", Renderer::TEXTURE_NONE);
	rdr->setShaderResource("gLightTex2", Renderer::TEXTURE_NONE);
	if(use6Axes)
	{
		rdr->setShaderResource("gLightTex3", Renderer::TEXTURE_NONE);
		rdr->setShaderResource("gLightTex4", Renderer::TEXTURE_NONE);
	}
	rdr->applyConstantsWithoutDrawing();
}

void mgfx::renderLowFreq(const RenderingData & data, const RenderingSettings & settings, TextureID dstBuffer, TextureID depthBuffer, const CSM & csm)
{
	if(!settings.RenderParticlesCS)
		return;

	static bool generated = false;
	if(!generated)
	{
		init3DTextures(data);
		generated = true;
	}

	//updateLightTexturesCS(data, csm);

	//Renderer * rdr = Renderer::Instance;

	//rdr->setRenderTargets(1, &dstBuffer, depthBuffer);

	//rdr->setPrimitiveType(TRIANGLE_LIST);
	//rdr->setVertexFormat(VertexPositionNormalTangentTexture::VertexFormat);

	//
	//rdr->setShader(ShaderRenderObj);

	//rdr->setShaderResource("gLightTex0", LightTex[0]);
	//rdr->setShaderResource("gLightTex1", LightTex[1]);
	//rdr->setShaderResource("gLightTex2", LightTex[2]);
	//if(use6Axes)
	//{
	//	rdr->setShaderResource("gLightTex3", LightTex[3]);
	//	rdr->setShaderResource("gLightTex4", LightTex[4]);
	//}
	//

	//rdr->setShaderFloatVector("gLightVolScale",(float*)&LightVolumeScale);
	//rdr->setShaderFloatVector("gLightVolPos", (float*)&LightVolumePos);
	//rdr->setShaderFloatVector("gEyePosW",(float*)&data.EyePosition);

	//XMMATRIX view, proj;
	//view = XMLoadFloat4x4(&data.ViewMatrix);
	//proj = XMLoadFloat4x4(&data.ProjMatrix);

	//Mesh::Part meshPart = TestMesh->GetParts()[0];
	//rdr->setVertexBuffer(meshPart.VB);
	//rdr->setIndexBuffer(meshPart.IB);

	//for(uint z = 1; z < max(groupSize * groupsZ, 1) - 1; z+=1)
	//{
	//	for(uint y = 1; y < max(groupSize * groupsY, 1) - 1; y+=1)
	//	{
	//		for(uint x = 1; x < max(groupSize * groupsX, 1) - 1; x+=1)
	//for(uint z = 0; z < groupSize * groupsZ; z+=1)
	//{
	//	for(uint y = 0; y < groupSize * groupsY; y+=1)
	//	{
	//		for(uint x = 0; x < groupSize * groupsX; x+=1)
	//		{
	//			XMMATRIX world = XMMatrixMultiply(
	//				XMMatrixScaling(0.03f, 0.03f, 0.03f),
	//				XMMatrixTranslationFromVector(LightVolumePos + XMVectorSet(x, y, z, 0) * LightVolumeScale)
	//			);
	//			XMMATRIX wvp = XMMatrixMultiply(world, XMMatrixMultiply(view, proj));

	//			rdr->setShaderMatrix("gWVP", (float*)&wvp);
	//			rdr->setShaderMatrix("gWorld", (float*)&world);

	//			Mesh::Part meshPart = TestMesh->GetParts()[0];
	//			rdr->setVertexBuffer(meshPart.VB);
	//			rdr->setIndexBuffer(meshPart.IB);
	//			rdr->drawIndexed();
	//		}
	//	}
	//}

	//rdr->setShaderResource("gLightTex0", NULL);
	//rdr->setShaderResource("gLightTex1", NULL);
	//rdr->setShaderResource("gLightTex2", NULL);
	//if(use6Axes)
	//{
	//	rdr->setShaderResource("gLightTex3", NULL);
	//	rdr->setShaderResource("gLightTex4", NULL);
	//}
	//

	//rdr->applyConstantsWithoutDrawing();

	//D3DPERF_BeginEvent(D3DCOLOR_RGBA(255, 0, 255, 255), L"particles");
	//Renderer * rdr = Renderer::Instance;
	//rdr->setRenderTargets(1, &dstBuffer, depthBuffer);

	//for(uint i = 0; i < data.PartSystems.NumElements; i++)
	//{
	//	updateLightTexturesCS(data, i, csm);
	//	renderParticles(data, i);
	//}
	//D3DPERF_EndEvent();
	
	D3DPERF_BeginEvent(D3DCOLOR_RGBA(255, 0, 255, 255), L"particles");
	renderParticlesBigTex(data, dstBuffer, depthBuffer, csm);
	D3DPERF_EndEvent();
}

